package com.video.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.video.constants.SysConstants;
import com.video.dao.*;
import com.video.dto.VlogDTO;
import com.video.entity.*;
import com.video.exception.VideoException;
import com.video.result.AppHttpCodeEnum;
import com.video.result.YesOrNo;
import com.video.utils.BeanCopyUtils;
import com.video.utils.JwtUtil;
import com.video.utils.RedisCache;
import com.video.vo.*;
import com.video.result.ResultVO;
import com.video.service.VlogsService;
import io.jsonwebtoken.Claims;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * (Vlogs)表服务实现类
 *
 * @author baoshuai
 * @since 2022-12-14 21:02:16
 */
@Service("vlogsService")
public class VlogsServiceImpl extends ServiceImpl<VlogsMapper, Vlogs> implements VlogsService {

    @Resource
    private LikedVlogMapper likedVlogMapper;

    @Resource
    private UsersMapper usersMapper;

    @Resource
    private VlogsMapper vlogsMapper;

    @Resource
    private TagVlogMapper tagVlogMapper;

    @Resource
    private TagsMapper tagsMapper;

    @Resource
    private RedisCache redisCache;

    @Override
    public ResultVO pageList(Integer pageNum, Integer pageSize, String keyword) {
        Page<Vlogs> page = new Page<>(pageNum, pageSize);

        LambdaQueryWrapper<Vlogs> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .like(StringUtils.hasText(keyword), Vlogs::getTitle, keyword)
                .or()
                .like(StringUtils.hasText(keyword), Vlogs::getContent, keyword);

        page(page, queryWrapper);

        PageVo pageVo = new PageVo(page.getTotal(), page.getRecords());

        return ResultVO.success(pageVo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResultVO publishVlog(PublishVlogVo publishVlogVo) {
        if (!StringUtils.hasText(publishVlogVo.getUrl())) {
            throw new VideoException(AppHttpCodeEnum.VLOG_NOT_EXIST);
        }
        User user = usersMapper.selectById(publishVlogVo.getUserId());
        if (Objects.isNull(user)) {
            throw new VideoException(AppHttpCodeEnum.USER_NOT_EXIST);
        }
        Vlogs vlogs = BeanCopyUtils.copyBean(publishVlogVo, Vlogs.class);
        save(vlogs);

        //添加视频标签
        //获取自定义和选择的标签
        VlogTagVo vlogTagVo = publishVlogVo.getVlogTagVo();

        //添加选择的标签
        saveSelectTag(vlogTagVo.getSelectTags(), vlogs.getId());

        //获取所有标签
        List<String> tagNameList = getTagNameList();

        //添加自定义的标签
        saveCustomTag(vlogTagVo.getCustomTags(), tagNameList, vlogs.getId());

        return ResultVO.success();
    }

    private void saveCustomTag(List<String> customTags, List<String> tagNameList, Long vlogId) {
        TagVlog tagVlog = new TagVlog().setVlogId(vlogId);
        for (String customTag : customTags) {
            Tags tag;
            if (tagNameList.contains(customTag)) {
                //自定义标签已存在
                //根据名称查询标签
                tag = getTagByName(customTag);
            } else {
                //自定义标签不存在
                //添加标签
                tag = new Tags().setTag(customTag).setTodayCounts(0).setTotalCounts(0);
                tagsMapper.insert(tag);

            }
            tagVlog.setTagId(tag.getId());
            tagVlog.setId(null);
            tagVlogMapper.insert(tagVlog);
        }
    }

    private void saveSelectTag(List<Long> selectTags, Long vlogId) {
        for (Long selectTag : selectTags) {
            TagVlog tagVlog = new TagVlog().setVlogId(vlogId).setTagId(selectTag);
            tagVlogMapper.insert(tagVlog);
        }
    }

    /**
     * 获取所有标签名
     *
     * @return 标签名列表
     */
    private List<String> getTagNameList() {
        List<Tags> tagsList = tagsMapper.selectList(null);
        return tagsList.stream()
                .map(Tags::getTag)
                .collect(Collectors.toList());
    }

    private void deleteOriginVlogTag(Long vlogId) {
        LambdaQueryWrapper<TagVlog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TagVlog::getVlogId, vlogId);
        tagVlogMapper.delete(queryWrapper);
    }

    private Tags getTagByName(String customTag) {
        LambdaQueryWrapper<Tags> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Tags::getTag, customTag);
        return tagsMapper.selectOne(queryWrapper);
    }


    @Override
    public ResultVO changePrivateOrPublic(Long userId, Long vlogId, Integer type) {
        Vlogs vlogs = getVlogByUserIdAndVlogId(userId, vlogId);

        if (Objects.isNull(vlogs)) {
            throw new VideoException(AppHttpCodeEnum.VLOG_NOT_EXIST);
        }

        if (type.equals(YesOrNo.YES.type)) {
            vlogs.setIsPrivate(1);
        } else {
            vlogs.setIsPrivate(2);
        }
        updateById(vlogs);

        return ResultVO.success();
    }

    @Override
    public ResultVO modifyTitle(VlogDTO vlogDTO) {
        Vlogs vlogs = getVlogByUserIdAndVlogId(vlogDTO.getUserId(), vlogDTO.getVlogId());

        if (Objects.isNull(vlogs)) {
            throw new VideoException(AppHttpCodeEnum.VLOG_NOT_EXIST);
        }
        vlogs.setTitle(vlogDTO.getTitle());
        updateById(vlogs);

        return ResultVO.success();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void unlikeVlog(Long userId, Long vlogId) {
        User user = usersMapper.selectById(userId);
        if (Objects.isNull(user)) {
            throw new VideoException(AppHttpCodeEnum.USER_NOT_EXIST);
        }
        Vlogs vlog = vlogsMapper.selectById(vlogId);
        if (Objects.isNull(vlog)) {
            throw new VideoException(AppHttpCodeEnum.VLOG_NOT_EXIST);
        }

        LikedVlog likedVlog = getLikedVlogByUserIdAndVlogId(userId, vlogId);
        if (Objects.isNull(likedVlog)) {
            throw new VideoException(AppHttpCodeEnum.SYSTEM_ERROR);
        }

        if (0 == likedVlog.getStatus()) {
            throw new VideoException(AppHttpCodeEnum.SYSTEM_ERROR);
        }

        // 更新用户点赞状态
        likedVlog.setStatus(0);
        likedVlogMapper.updateById(likedVlog);

        //更新视频点赞数
        vlog.setLikeCounts(vlog.getLikeCounts() - 1);
        vlogsMapper.updateById(vlog);

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void likeVlog(Long userId, Long vlogId) {
        User user = usersMapper.selectById(userId);
        if (Objects.isNull(user)) {
            throw new VideoException(AppHttpCodeEnum.USER_NOT_EXIST);
        }
        Vlogs vlog = vlogsMapper.selectById(vlogId);
        if (Objects.isNull(vlog)) {
            throw new VideoException(AppHttpCodeEnum.VLOG_NOT_EXIST);
        }

        LikedVlog likedVlog = getLikedVlogByUserIdAndVlogId(userId, vlogId);
        if (Objects.isNull(likedVlog)) {
            LikedVlog build = LikedVlog.builder()
                    .userId(userId)
                    .vlogId(vlogId)
                    .status(1).build();
            likedVlogMapper.insert(build);
        } else {
            if (1 == likedVlog.getStatus()) {
                throw new VideoException(AppHttpCodeEnum.SYSTEM_ERROR);
            }

            likedVlog.setStatus(1);
            likedVlogMapper.updateById(likedVlog);
        }

        //更新视频点赞数
        vlog.setLikeCounts(vlog.getLikeCounts() + 1);
        vlogsMapper.updateById(vlog);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResultVO modifyVlog(VlogDTO vlogDTO) {
        Long userId = vlogDTO.getUserId();
        Long vlogId = vlogDTO.getVlogId();
        if (Objects.isNull(usersMapper.selectById(userId))) {
            throw new VideoException(AppHttpCodeEnum.USER_NOT_EXIST);
        }
        if (Objects.isNull(vlogsMapper.selectById(vlogId))) {
            throw new VideoException(AppHttpCodeEnum.VLOG_NOT_EXIST);
        }
        if (Objects.isNull(getVlogByUserIdAndVlogId(userId, vlogId))) {
            throw new VideoException(AppHttpCodeEnum.NO_POWER_MODIFY_VLOG);
        }

        //修改视频标题
        modifyTitle(vlogDTO);

        //修改标签
        //删除原有的标签
        deleteOriginVlogTag(vlogDTO.getVlogId());

        //修改选择的视频标签
        saveSelectTag(vlogDTO.getVlogTagVo().getSelectTags(), vlogId);
        //修改自定义的视频标签
        saveCustomTag(vlogDTO.getVlogTagVo().getCustomTags(), getTagNameList(), vlogId);

        return ResultVO.success();
    }

    @Override
    public QueryVlogsVo queryVlogAndLikeInfo(Long id, String token) {
        Vlogs vlog = getById(id);
        QueryVlogsVo queryVlogsVo = BeanCopyUtils.copyBean(vlog, QueryVlogsVo.class);

        try {
            Claims claims = JwtUtil.parseJWT(token);
            String userId = claims.getSubject();
            LoginUser loginUser = redisCache.getCacheObject(SysConstants.USER_LOGIN + userId);
            User user = loginUser.getUser();
            if (Objects.isNull(user)) {
                return queryVlogsVo;
            }

            //查询是否点赞
            LambdaQueryWrapper<LikedVlog> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(LikedVlog::getVlogId, id);
            queryWrapper.eq(LikedVlog::getUserId, userId);
            LikedVlog likedVlog = likedVlogMapper.selectOne(queryWrapper);
            Integer status = likedVlog.getStatus();
            if (1 == status) {
                queryVlogsVo.setIsLike(true);
            }
        } catch (Exception e) {
        }
        return queryVlogsVo;
    }


    private LikedVlog getLikedVlogByUserIdAndVlogId(Long userId, Long vlogId) {
        LambdaQueryWrapper<LikedVlog> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LikedVlog::getUserId, userId);
        queryWrapper.eq(LikedVlog::getVlogId, vlogId);
        return likedVlogMapper.selectOne(queryWrapper);
    }

    private Vlogs getVlogByUserIdAndVlogId(Long userId, Long vlogId) {
        LambdaQueryWrapper<Vlogs> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Vlogs::getId, vlogId);
        queryWrapper.eq(Vlogs::getUserId, userId);
        return getOne(queryWrapper);
    }

}

